<?php

namespace Juheip\IpService;

use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use Juheip\IpService\contract\PlatformInterface;
use Juheip\IpService\exception\JuheException;
use Juheip\IpService\log\PlatFormsLogger;
use Psr\Http\Message\ResponseInterface;
use think\exception\RouteNotFoundException;

class PlatformRequest
{
    /**
     * @var Guzzle 客户端
     */
    private $client;

    /**
     * @var Logger 日志实例
     */
    private $logger;

    /**
     * @var Config 配置
     */
    private $juheip_platforms_config;

    /**
     * @var PlatformInterface 平台实例
     */
    private $platform;

    /**
     * @var array 单次请求上下文(用于日志)
     */
    private $context = [];

    private $options = [
        'timeout' => 60,
        'connect_timeout' => 10,
        'headers' => [
            'User-Aget' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36',
            'Accept' => 'application/json'
        ]
    ];

    public function __construct(PlatformInterface $platform, array $config = [])
    {
        $this->platform = $platform;
        $this->setRequestHeader($config);

        $this->juheip_platforms_config = new Config();

        if ($this->juheip_platforms_config->get('log.enable')) {
            $this->logger = new PlatFormsLogger(
                $this->juheip_platforms_config->get('log.log_name', ''),
                $this->juheip_platforms_config->get('log.path'),
                $this->juheip_platforms_config->get('log.level'),
                $this->juheip_platforms_config->get('log.keep_days'),
            );
        }
    }

    public function setRequestHeader($headers)
    {
        $this->options = array_merge_recursive($this->options, $headers);
        $this->client = new Client($this->options);
        return $this;
    }

    public function formRequest(string $method, string $url, array $params = [], array $options = [], array $headers = []): array
    {
        return $this->request($method, $url, $params, $options, $headers, 'form');
    }

    public function request(string $method, string $url, array $params = [], array $options = [], array $headers = [], $format = 'json'): array
    {
        $this->context = [
            'platform' => $this->platform::class,
            'request_id' => uniqid('req_'),
            'method' => strtoupper($method),
            'url' => $url,
            'start_time' => microtime(true)
        ];

        try {
            $requestHeaders = $this->prepareHeaders($headers);
            $requestOptions = $this->prepareOptions($method, $params, $options, $format);
            $this->logRequest(array_merge($requestHeaders, $requestOptions));
            $response = $this->client->request($method, $url, array_merge($requestHeaders, $requestOptions));

            $result = $this->parseResponse($response);
            $this->logResponse($result, $response);

            return $result;
        } catch (RequestException $e) {
            $error = $this->handleRequestException($e);
            $this->logError($error, $e);

            return $error;
        } catch (GuzzleException $e) {
            $error = [
                'success' => false,
                'code' => 500,
                'message' => 'HTTP 请求失败：' . $e->getMessage(),
                'data' => null,
                'raw' => null, // 原始响应（异常时可能为 null）
            ];

            $this->logError($error, $e);

            return $error;
        } catch (Exception $e) {
            $error = [
                'success' => false,
                'code' => 500,
                'message' => '系统错误：' . $e->getMessage(),
                'data' => null,
                'raw' => null
            ];

            $this->logError($error, $e);

            return $error;
        }
    }

    private function prepareHeaders(array $headers = []): array
    {
        if (empty($headers)) {

            return [];
        }

        return ['headers' => $headers];
    }

    private function prepareOptions(string $method, array $params, array $options, $format = 'json'): array
    {
        $method = strtoupper($method);
        $requestOptions = $options;

        if ($method === 'GET') {
            $requestOptions ['query'] = $params;
        } else {
            // if (!isset($requestOptions ['body']) && !isset($requestOptions ['form_params'])) {
            switch ($format) {
                case 'json':
                    $requestOptions ['json'] = $params;
                    break;
                case 'form':
                    $requestOptions ['form_params'] = $params;
                    break;
            }
        }

        return $requestOptions;
    }

    private function parseResponse(ResponseInterface $response): array
    {
        $statusCode  = $response->getStatusCode();
        $body        = $response->getBody()->getContents();
        $contentType = $response->getHeaderLine('Content-Type');
        $data        = null;

        if (strpos($contentType, 'application/json') !== false) {
            $data = json_decode($body, true);
            if (json_last_error() !== JSON_ERROR_NONE) {

                return [
                    'success' => false,
                    'code' => $statusCode,
                    'message' => '响应 JSON 解析失败：' . json_last_error_msg(),
                    'data' => null,
                    'raw' => $body,
                ];
            }
        } else {
            $data = $body;
        }

        return [
            'success' => true,
            'code' => $statusCode,
            'message' => '请求成功',
            'data' => $data,
            'raw' => $body
        ];
    }

    private function handleRequestException(RequestException $e): array
    {
        $message = '请求异常：' . $e->getMessage();
        $statusCode = 500;
        $rawResponse = null;
        $responseData = null;

        if ($e->hasResponse()) {
            $response = $e->getResponse();
            $statusCode = $response->getStatusCode();
            $rawResponse = $response->getBody()->getContents();

            if (strpos($response->getHeaderLine('Content-Type'), 'application/json') !== false) {
                $responseData = json_decode($rawResponse, true);
            }
        }

        return [
            'success' => false,
            'code' => $statusCode,
            'message' => $message,
            'data' => $responseData,
            'raw' => $rawResponse
        ];
    }

    private function logRequest(array $options): void
    {
        if (!$this->logger) return;

        $params = $options ['query'] ?? ($options ['json'] ?? []);
        $this->context ['params']  =  $params;
        $this->context ['headers'] =  $options ['headers'] ?? [];

        $this->logger->info('发送请求', $this->context);
    }

    private function logResponse(array $result, ResponseInterface $response): void
    {
        if (!$this->logger) return;

        $this->context ['status_code'] = $response->getStatusCode();
        $this->context ['duration_ms'] = round((microtime(true) - $this->context ['start_time']) * 1000, 2);
        $this->context ['response'] = $result ['data'];

        $this->logger->info('请求完成', $this->context);
    }

    private function logError(array $error, \Throwable $e): void
    {
        if (!$this->logger) return;

        $this->context ['status_code'] = $error ['code'];
        $this->context ['duration_ms'] = round((microtime(true) - $this->context ['start_time']) * 1000, 2);
        $this->context ['error'] = $error ['message'];
        $this->context ['statck_trace'] = $e->getTraceAsString();

        $this->logger->error('请求异常', $this->context);
    }
}